package com.weifly.weistock.module.stockdata.impl;

import com.weifly.weistock.bo.MergeRecordResult;
import com.weifly.weistock.core.market.bo.StockDayBO;
import com.weifly.weistock.core.market.bo.StockDividendBO;
import com.weifly.weistock.core.market.bo.StockKLineBO;
import com.weifly.weistock.module.stockdata.StockDataConverter;
import com.weifly.weistock.module.stockdata.StockDataHoldService;
import com.weifly.weistock.module.stockdata.StockDataStoreService;
import com.weifly.weistock.module.stockdata.bo.GetDayListRequest;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 股票数据hold服务
 *
 * @author weifly
 * @since 2021/6/11
 */
public class StockDataHoldServiceImpl implements StockDataHoldService {

    /**
     * 股票数据集合
     */
    private SortedMap<String, StockKLineBO> stockDataMap = new TreeMap<>();

    private StockDataStoreService stockDataStoreService;

    public void setStockDataStoreService(StockDataStoreService stockDataStoreService) {
        this.stockDataStoreService = stockDataStoreService;
    }

    @Override
    public void updateStockDataList(List<StockKLineBO> stockDataList) {
        synchronized (this) {
            this.stockDataMap.clear();
            for (StockKLineBO stockKLineBO : stockDataList) {
                this.stockDataMap.put(stockKLineBO.getStockCode(), stockKLineBO);
            }
        }
    }

    @Override
    public MergeRecordResult updateStockData(StockKLineBO stockData) {
        StockKLineBO target = this.stockDataStoreService.loadStockData(stockData.getStockCode());
        if (target == null) {
            target = new StockKLineBO();
        }
        target.setStockCode(stockData.getStockCode());
        target.setStockName(stockData.getStockName());
        target.setStockCatalog(stockData.getStockCatalog());
        MergeRecordResult mergeRecordResult = new MergeRecordResult();
        StockDataConverter.mergeDayList(stockData, target, mergeRecordResult);
        StockDataConverter.calcFrontPrice(target);
        this.saveAndUpdate(target);
        return mergeRecordResult;
    }

    @Override
    public List<StockKLineBO> getStockDataList() {
        synchronized (this) {
            return new ArrayList<>(this.stockDataMap.values());
        }
    }

    @Override
    public StockKLineBO getStockData(String stockCode) {
        synchronized (this) {
            return this.stockDataMap.get(stockCode);
        }
    }

    @Override
    public List<StockDayBO> getDayList(GetDayListRequest request) {
        List<StockDayBO> resultList = new ArrayList<>();
        if (StringUtils.isBlank(request.getStockCode())) {
            return resultList;
        }
        StockKLineBO stockKLineBO = null;
        synchronized (this) {
            stockKLineBO = this.stockDataMap.get(request.getStockCode());
        }
        if (stockKLineBO == null) {
            return resultList;
        }

        List<StockDayBO> dayList = stockKLineBO.getDayList();
        int limit = request.getLimit();
        // 降序遍历
        for (int i = dayList.size() - 1; i >= 0; i--) {
            StockDayBO stockDayBO = dayList.get(i);
            if (!this.filterRecord(stockDayBO, request)) {
                resultList.add(stockDayBO);
                if (resultList.size() >= limit) {
                    break;
                }
            }
        }
        return resultList;
    }

    // 需要过滤的记录，则返回true
    private boolean filterRecord(StockDayBO stockDayBO, GetDayListRequest request) {
        if (StringUtils.isNotBlank(request.getDate())) {
            int dataCompare = stockDayBO.getDay().compareTo(request.getDate());
            if (dataCompare >= 0) {
                // record date 大或相等，需要过滤
                return true;
            }
        }
        return false;
    }

    @Override
    public void updateStockDividend(StockDividendBO stockDividend) {
        StockKLineBO target = this.stockDataStoreService.loadStockData(stockDividend.getStockCode());
        if (target == null) {
            target = new StockKLineBO();
        }
        Map<String, StockDividendBO> stockDividendMap = target.getDividendList().stream().collect(Collectors.toMap(StockDividendBO::getDay, Function.identity()));
        stockDividendMap.put(stockDividend.getDay(), stockDividend);
        target.getDividendList().clear();
        target.getDividendList().addAll(stockDividendMap.values());
        target.getDividendList().sort((day1, day2) -> day1.getDay().compareTo(day2.getDay()));
        StockDataConverter.calcFrontPrice(target);
        this.saveAndUpdate(target);
    }

    private void saveAndUpdate(StockKLineBO stockKLine) {
        // 保存文件
        this.stockDataStoreService.saveStockData(stockKLine);
        // 更新缓存
        synchronized (this) {
            this.stockDataMap.put(stockKLine.getStockCode(), stockKLine);
        }
    }
}
